﻿using System.Xml;
using System.Text;
using System.Windows.Forms;
using SdmxMl.Common;

namespace SdmxMl.Structure
{
    /// <summary>
    /// CodeListType defines the contents of a codelist. This includes an ID, the agency which 
    /// maintains the codelist, its version, and a URL where it is located. Elements are provided 
    /// for supplying a name and the codes. It is acceptable to provide only the id, name, and uri 
    /// fields at a minimum, with the uri pointing to an SDMX Structure message containing complete 
    /// details on the codelist. (This is termed an "external reference".) If an external reference 
    /// is being made, the isExternalReference attribute must be set to "true". The urn attribute 
    /// holds a valid SDMX Registry URN (see SDMX Registry Specification). The validFrom and validTo 
    /// attributes provide inclusive dates for providing supplemental validity information about the version.
    /// </summary>
    public class CodeListType : Artefact
    {
        #region Properties

        private CodeList codeList;
        public CodeList CodeList
        {
            get { return codeList; }
            set { codeList = value; }
        }

        #endregion //Properties

        #region Constructors

        public CodeListType()
            : base()
        {
            Init();
        }

        private void Init()
        {
            codeList = new CodeList();
        }

        public CodeListType(XmlNode nodeArtefact, SdmxNamespaceManager nsmgr) 
            : base(nodeArtefact, nsmgr)
        {
            Init();
            codeList.ReadXml(nodeArtefact, nsmgr, "./structure:Code");
        }

        #endregion //Constructors

        #region Override

        public override void WriteXmlInsider(XmlTextWriter xw)
        {
            string prefix = "structure";
            foreach (CodeType  c in codeList)
                c.WriteXml(xw, prefix, "Code");
        }

        #endregion //Override

        #region Tree

        public override TreeNode FillNode(TreeNode parentNode)
        {
            TreeNode t = base.FillNode(parentNode);
            TreeNode tc = new TreeNode(codeList.ToString(), 1, 1);
            tc.Tag = codeList;
            t.Nodes.Add(tc);
            codeList.FillTree(tc);
            return t;
        }
        #endregion //Tree

        #region Check

        public override bool Check(out string diagnostic)
        {
            StringBuilder sb = new StringBuilder();

            //TODO: Checkings

            // Check all codes have valid systax

            // check all parents exists, set hierarchy flag if missing

            // check uniqueness of all codes

            //Return diagnostic 
            diagnostic = sb.ToString();
            bool hasError = false;

            return hasError;
        }
        #endregion //Check

        #region Artefact Type

        public override Manager.SdmxArtefactType ArType
        {
            get { return Manager.SdmxArtefactType.CodeLists; }
        }

        #endregion

        #region Default TextFormat

        /// <summary>
        /// When no text format is given in concept or DSD item, it is helpful to determine a default format according to codes values
        /// </summary>
        /// <returns>TextFormatType Object with its property Textype set according to detected codes types </returns>
        public TextFormatType GetDefaultTextFormat()
        {
            // Default to generic string
            TextFormatType tft = new TextFormatType();
            tft.TextType = TextTypeType.String;

            // Check for Integer of Long (helpful for DB format or SAS format)
            bool allDigit = true;
            bool longValue = false;
            int maxSize = 2;
            foreach (CodeType c in CodeList)
            {
                maxSize = System.Math.Max(maxSize, c.Id.Length);
                for (int i = 0; i < c.Id.Length; i++)
                {
                    // Valid for Integer ot Long, sign accepted, or numeric starting with 0 and other number is text
                    if ((!(System.Char.IsDigit(c.Id[i]) == true || i == 0 && c.Id[0] == '-')) ||
                        (c.Id.Length > 0 && c.Id[0] == '0'))
                    {
                        allDigit = false;
                        break;
                    }
                }
                // int or long ?
                if (longValue == false)
                {
                        int val;
                        if (int.TryParse(c.Id, out val) == false)
                            longValue = true;
                }

            }
            if (allDigit)
            {
                tft.TextType = longValue ? TextTypeType.Long : TextTypeType.Integer;
            }

            tft.maxLength = maxSize.ToString();
            return tft;
        }
        


        #endregion
    }
}
